package com.ticket.sass.provider.business.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ticket.sass.common.entity.provider.TenantEntity;
import com.ticket.sass.common.entity.tenant.CinemaEntity;
import com.ticket.sass.common.entity.tenant.TenantAccountEntity;
import com.ticket.sass.common.entity.tenant.TenantCinemaMapEntity;
import com.ticket.sass.common.entity.tenant.TenantFundFlowEntity;
import com.ticket.sass.common.exception.enums.ErrorCode;
import com.ticket.sass.common.exception.exception.BadRequestException;
import com.ticket.sass.provider.business.TenantBusiness;
import com.ticket.sass.provider.dto.TenantListOutput;
import com.ticket.sass.provider.dto.input.tenant.TenantAddInput;
import com.ticket.sass.provider.dto.input.tenant.TenantListInput;
import com.ticket.sass.provider.dto.input.tenant.TenantUpdInput;
import com.ticket.sass.provider.dto.input.tenant.TransactionInput;
import com.ticket.sass.provider.dto.output.TransactionDataOutput;
import com.ticket.sass.provider.dto.output.TransactionOutput;
import com.ticket.sass.provider.service.LabModel;
import com.ticket.sass.provider.service.PageModel;
import com.ticket.sass.provider.service.impl.*;
import com.ticket.sass.provider.util.CompareUtil;
import com.ticket.sass.provider.util.ModelUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.TypeToken;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author ywb
 * @date 2024-03-29 14:29
 */
@Slf4j
@Service
@AllArgsConstructor
public class TenantBusinessImpl implements TenantBusiness {
    final ModelUtil modelUtil;
    final TenantServiceImpl service;
    final CinemaServiceImpl cinemaService;
    final TenantAccountServiceImpl accountsService;
    final TenantFundFlowServiceImpl tenantFundFlowsService;
    final TenantCinemaMapServiceImpl tenantCinemaMapService;
    

    
    @Override
    public PageModel<TenantListOutput> list(TenantListInput input) {
        IPage<TenantEntity> filmEntityIPage = service.iPage(input);
        
        // 转换租户列表对象为输出对象
        List<TenantListOutput> outputs = modelUtil.listToList(filmEntityIPage.getRecords(), new TypeToken<List<TenantListOutput>>(){}.getType());
        
        
        List<Long> tenantIds = outputs.stream().map(TenantListOutput::getId).collect(Collectors.toList());
        
        // 余额
        Map<Long, BigDecimal> balancesByTenantIds = accountsService.getBalancesByTenantIds(tenantIds);
        
        // 影院关联关系
        Map<Long, List<TenantCinemaMapEntity>> cinemasByTenantIds = tenantCinemaMapService.getCinemasByTenantIds(tenantIds);
        
        List<Long> allCinemaIds = new ArrayList<>();
        
        for (Map.Entry<Long, List<TenantCinemaMapEntity>> entry : cinemasByTenantIds.entrySet()) {
            List<TenantCinemaMapEntity> cinemaList = entry.getValue();
            for (TenantCinemaMapEntity cinemaMapEntity : cinemaList) {
                allCinemaIds.add(cinemaMapEntity.getCinemaId());
            }
        }
        List<LabModel> cinemaServiceLabModels = allCinemaIds.size() > 0 ?
            cinemaService.getLabModels(new QueryWrapper<CinemaEntity>().in("id", allCinemaIds)) :
            new ArrayList<>();
        
        outputs.forEach(output -> {
            // 填充影院关联信息
            List<LabModel> cinemas = new ArrayList<>();
            List<TenantCinemaMapEntity> tenantCinemaMapEntities = cinemasByTenantIds.get(output.getId());
            if (tenantCinemaMapEntities != null) {
                for (TenantCinemaMapEntity cinemaMapEntity : tenantCinemaMapEntities) {
                    LabModel labModel = cinemaServiceLabModels.stream()
                        .filter(l -> Objects.equals(cinemaMapEntity.getCinemaId(), l.getId()))
                        .findFirst()
                        .orElse(null);
                    if (labModel != null) {
                        cinemas.add(labModel);
                    }
                }
            }
            output.setCinemas(cinemas);
            
            // 填充影院数量
            output.setCinemaCount(cinemas.size());
            
            output.setBalance(balancesByTenantIds.get(output.getId()));
        });
        
        
        // 返回分页模型对象，假设总记录数为租户列表的大小
        return new PageModel<>(filmEntityIPage.getTotal(), outputs);
    }
    
    @Override
    public void add(TenantAddInput input) {
        if (service.count(new QueryWrapper<TenantEntity>().eq("key", input.getKey())) > 0){
            throw new BadRequestException(
                ErrorCode.BAD_REQUEST,
                "key 已被占用"
            );
        }
        
        // 将输入对象转换为租户实体对象并保存
        TenantEntity tenantEntity = modelUtil.mapToMap(input, TenantEntity.class);
        service.save(tenantEntity);
        
        List<TenantCinemaMapEntity> collect = input.getCinemaIds().stream().map(cinemaId -> new TenantCinemaMapEntity(cinemaId, tenantEntity.getId())).collect(Collectors.toList());
        tenantCinemaMapService.saveBatch(collect);
        
        
        TenantAccountEntity tenantAccountEntity = new TenantAccountEntity(new BigDecimal("0.0"), tenantEntity.getId());
        accountsService.save(tenantAccountEntity);
    }
    
    @Override
    public void upd(TenantUpdInput input) {
        // 将输入对象转换为租户实体对象并更新
        TenantEntity tenantEntity = modelUtil.mapToMap(input, TenantEntity.class);
        service.updateById(tenantEntity);
        
        List<Long> oldCinemaIds = tenantCinemaMapService.getCinemaIdsByTenantId(tenantEntity.getId());
        
        List<Long> newCinemaIds = input.getCinemaIds();
        
        // 分离数据
        CompareUtil<Long> compareUtil = new CompareUtil<>(oldCinemaIds, newCinemaIds);
        // 删除
        
        
        tenantCinemaMapService.removeBy(tenantEntity.getId(), compareUtil.getDel());
        // 新增
        saveBatchCinemaMaps(compareUtil.getInsert(), tenantEntity.getId());
        
        
        
    }
    
    @Override
    public TransactionDataOutput transactionInfo(TransactionInput input) {
        TransactionDataOutput output = new TransactionDataOutput();
        Long id = input.getId();
        
        output.setBalance(accountsService.getBalance(id));
        
        IPage<TenantFundFlowEntity> page = tenantFundFlowsService.iPage(id, input);
        List<TransactionOutput> outputs = modelUtil.listToList(
            page.getRecords(),
            new TypeToken<List<TransactionOutput>>(){}.getType()
        );
        
        output.setPage(new PageModel<>(page.getTotal(), outputs));
        return output;
    }
    
    
    /**
     * 批量保存关联关系
     * @param cinemaIds 影院ID
     * @param planId 计划ID
     */
    public void saveBatchCinemaMaps(List<Long> cinemaIds, Long planId){
        if (cinemaIds.size() > 0){
            Long count = cinemaService.countByIds(cinemaIds);
            if (!Objects.equals(cinemaIds.get(0),0) && count != cinemaIds.size()){
                throw new BadRequestException(
                    ErrorCode.INPUT_REQUEST,
                    "关联影院数据有误"
                );
            }
            List<TenantCinemaMapEntity> cinemas = cinemaIds.stream().map(
                id -> new TenantCinemaMapEntity(id, planId)
            ).collect(Collectors.toList());
            tenantCinemaMapService.saveBatch(cinemas);
        }
    }
}
